/*
 * etco2.c
 *
 *  Created on: 11-08-2012
 *      Author: Acer
 */

/* return 1 if OK
 * 0 - if problem
 */

#include "etco2.h"

#define U8_INC(x) 	if(255 == (x)){	(x) = 0; } else{(x)++;}

UART_RX_Circular_Buffer rb;

extern xSemaphoreHandle xEtco2Received;
extern xSemaphoreHandle xBreathParamsReceived;

void SetupETCO2Module()
{
	UART2_Config(38400);
	UART2_PrintStr("<D642>");	//configuration: 64 -> 100Hz, 2 -> only CO2
	if( 1 == IsResponseReceived("D642") )
	{
		rb.head = 0;
		rb.tail = 0;
		//printf("Skonfigurowalem ETCO2\n\r");
	}
}



void UART2_IRQHandler()
{
	volatile uint8_t stat;
	stat = (LPC_UART2->IIR & 0x0f);
	LPC_UART2->IER &= ~(1U<<0);								// wylacz przerwania od RBR Interrupt enabled (Receive Buffer)

	uint8_t recByte;
	recByte = UART2_Getchar();

	portBASE_TYPE xCheckWhatReceived = pdFALSE; //nie chcemy od razu budzic zadania
	//portBASE_TYPE xCheckWhatReceived2 = pdFALSE;

	if( 0x4==(stat&0x4) && 0x3C == recByte) //0x3C -> "<"															// jezeli takie przerwanie: Receive Data Available (RDA)
	{
		//do{
	//		rb.rx[rb.head] = UART2_Getchar();
		//	U8_INC(rb.head)
//			if(255 == rb.head)
//				rb.head = 0;
//			else
//				rb.head++;
		recByte = UART2_Getchar();
		if(0x57 == recByte || 0x77 == recByte)		//W -> wydech
		{
			LED_Toggle(1<<6);
			//printf("Odebralem info\n\r");
			xSemaphoreGiveFromISR( xEtco2Received, &xCheckWhatReceived );
			if( pdTRUE == xCheckWhatReceived)
			{
				portYIELD();
			}

		}
//		else if(0x50 == recByte)	//P
//		{
//			xSemaphoreGiveFromISR( xBreathParamsReceived, &xCheckWhatReceived2 );
//			if( pdTRUE == xCheckWhatReceived2)
//			{
//				portYIELD();
//			}
//		}
	}
	LPC_UART2->IER = (1<<0);
	//LED_Off(1<<6);
	return;
}

/*------------------------------------------------------------------------------
  configer UART2
 *------------------------------------------------------------------------------*/
void UART2_Config(int Baudrate)
{
    volatile uint64_t DLest;
    uint32_t pclkdiv, pclk;
    const uint8_t MulVal=2;
    const uint8_t DivAddVal=1;
    const int SystemFrequency = 100000000UL;

    LPC_SC->PCONP |=  (1U<<24);									// Turn on power to UART2
    LPC_PINCON->PINSEL0 |= (LPC_PINCON->PINSEL0 & ~0xf00000)|	//ensure being cleared
    					   (1U << 20)|							//P0.10 = TXD2
    					   (1U << 22);							//P0.11 = RXD2
    LPC_UART2->LCR = 0x00;
    LPC_UART2->LCR =  (3U<<0)|      	//8 bit
    				  (0U<<2)|			//1 stop bit
    				  (1U<<3)|			//parity enable
    				  (0x01U<<4)|		//even parity
    				  (1U<<7);			//DLAB=1

    LPC_UART2->FDR = (MulVal<<4) | (DivAddVal<<0);			//MulVal=2, DivAddVal=1

    pclkdiv = (LPC_SC->PCLKSEL1 >> 16) & 0x03; //select PCLK_UART2 in PCLKSEL1, bit 6 et 7

    // PCLK is 01 in
    switch ( pclkdiv ){
		case 0x00:
		default:
			pclk = SystemFrequency/4;
		break;
		case 0x01:
			pclk = SystemFrequency;
		break;
		case 0x02:
			pclk = SystemFrequency/2;
		break;
		case 0x03:
			pclk = SystemFrequency/8;
		break;
	}

    DLest = (pclk>>4)/((Baudrate*(MulVal+DivAddVal))/MulVal);   	//Set baud rate
    LPC_UART2->DLM = DLest>>8;			//BaudRateClock Lower 8 bits
    LPC_UART2->DLL = DLest%256;

    //FIFO
    LPC_UART2->FCR = (1U<<0)|      	// FIFO Enable
    				 (0x00U<<6);	// RX Trigger Level; 0->1znak, 1->4, 2->8, 3->14;


    LPC_UART2->LCR = (LPC_UART2->LCR) & (~0x80); //DLAB=0 to use TER
    LPC_UART2->TER = (1<<7);	//Transmit Enable = 1
}

__INLINE void  UART2_PrintChar (uint8_t ch)		//byl uint
{
   while (!(LPC_UART2->LSR & 0x20));
   LPC_UART2->THR  = ch;
}
__INLINE void UART2_PrintStr (uint8_t * str)
{
   while ((*str) != 0) {
      if (*str == '\n') {
         UART2_PrintChar(*str++);
         UART2_PrintChar('\r');
      } else {
         UART2_PrintChar(*str++);
      }
   }
}
uint8_t UART2_Getchar(void){
	while(!(LPC_UART2->LSR & 0x01));	/* Block until rx empty */
	return LPC_UART2->RBR;					/* Read receiver buffer register */
}

__INLINE void UART2_RxFIFO_Reset(void){
	LPC_UART2->FCR |=  (1U<<1);
}

uint8_t IsResponseReceived(uint8_t *str)
{
	uint8_t rbr = 0;
	do{
		rbr = UART2_Getchar();
	} while( *str != rbr );

	while( *str == rbr )
	{
		rbr = UART2_Getchar();
		*str++;
		if( 0x3E == rbr )
			return 1;
	}

	return 0;
}

uint8_t IsFrameWReceived()
{
	//printf("Szukam ramke\n\r");
	uint8_t idx = rb.tail;
	do{
		U8_INC(idx)
	}while(0x3C != rb.rx[idx]);
	rb.tail = idx;
	if(0x3C == rb.rx[idx])					//poczatek ramki "<"
	{
		if(0x77 == rb.rx[idx+1] || 0x57 == rb.rx[idx+1])	//w lub W
		{
			do{
				U8_INC(idx)
//				if(255 == idx)
//					idx = 0;
//				else
//					idx++;
				if(0x3E == rb.rx[idx])		//koniec ramki ">"
				{
					U8_INC(rb.tail)
				    U8_INC(rb.tail)
				    //printf("Ramka znaleziona\n\r");
					return 1;
				}
			}while(idx <= rb.head);
		}
		else{
			//printf("Jakas inna ramka\n\r");
			do{
				U8_INC(idx)
				if(0x3E == rb.rx[idx] && 0x3C == rb.rx[idx+1])
					rb.tail = idx+1;
			}while(idx <= rb.head);
		}
	}
	return 0;
}

float GetCO2Concentration()
{
	uint16_t CRC = 0;
	uint8_t val = 0;
	int8_t mantissa_idx = 16;
	uint32_t mantissa = 0;
	uint8_t exponent = 0;
	uint8_t sign = 0;
	float result;
	while( mantissa_idx > -1 )
	{
		//val =  rb.rx[rb.tail];
		val = UART2_Getchar();
		mantissa |= ( (uint32_t)( val << (mantissa_idx)));
		CRC += val;
		mantissa_idx -= 8;
		//U8_INC(rb.tail)
	}
	exponent = UART2_Getchar();//rb.rx[rb.tail];
	//U8_INC(rb.tail)
	CRC += exponent;
	sign = exponent & 0x80;
	exponent = exponent & 0x7F;
	CRC &= 0xFF;
	CRC ^= 0xF0;
	if((uint8_t)CRC != UART2_Getchar())//rb.rx[rb.tail])
	{
		//U8_INC(rb.tail)
		//printf("CRC error\n\r");
		UART2_RxFIFO_Reset();
		return -1;
	}
	//printf("Eksponenta = %d\n\rmantysa = %d\n\r", exponent, mantissa);
	UART2_RxFIFO_Reset();
	result = (float)((1<<(exponent-64))*(float)((float)mantissa/(float)0x1000000));
	//printf("%2.3f\n\r", result);
	if( result >= 0 )
		return result;
	else
		return -1;
}
